package cn.initcap.algorithm.swing.fractal.sierpinskitriangle;

import cn.initcap.algorithm.swing.AlgoVisHelper;
import cn.initcap.algorithm.swing.BaseAlgoFrame;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
 * @author initcap
 * @date 8/1/19 10:40 AM
 */
public class AlgoVisualizer {

    private static int DELAY = 40;
    private FractalData data;
    private BaseAlgoFrame frame;

    public AlgoVisualizer(int maxDepth) {

        data = new FractalData(maxDepth);
        int sceneWidth = (int) Math.pow(2, maxDepth);
        int sceneHeight = (int) Math.pow(2, maxDepth);

        EventQueue.invokeLater(() -> {
            frame = new BaseAlgoFrame("Fractal Visualizer", sceneWidth, sceneHeight) {
                @Override
                public void draw(Graphics graphics) {
                    Graphics2D g2d = (Graphics2D) graphics;
                    drawFractal(g2d, 0, sceneWidth, sceneHeight, 0);
                }
            };
            frame.addKeyListener(new AlgoKeyListener());
            new Thread(() -> {
                run();
            }).start();
        });
    }

    public static void main(String[] args) {

        int maxDepth = 9;

        new AlgoVisualizer(maxDepth);
    }

    private void run() {

        setData(data.depth);
    }

    private void setData(int depth) {
        data.depth = depth;

        frame.render(data);
        AlgoVisHelper.pause(DELAY);
    }

    public void addAlgoKeyListener() {
        frame.addKeyListener(new AlgoKeyListener());
    }

    private void drawFractal(Graphics2D g, int ax, int ay, int side, int depth) {

        if (side <= 1) {
            AlgoVisHelper.setColor(g, AlgoVisHelper.INDIGO);
            AlgoVisHelper.fillRectangle(g, ax, ay, 1, 1);
            return;
        }

        int bx = ax + side;
        int by = ay;

        int h = (int) (Math.sin(60.0 * Math.PI / 180.0) * side);
        int cx = ax + side / 2;
        int cy = ay - h;

        if (depth == data.depth) {
            AlgoVisHelper.setColor(g, AlgoVisHelper.INDIGO);
            AlgoVisHelper.fillTriangle(g, ax, ay, bx, by, cx, cy);
            return;
        }

        int abCenterx = (ax + bx) / 2;
        int abCentery = (ay + by) / 2;

        int acCenterx = (ax + cx) / 2;
        int acCentery = (ay + cy) / 2;

        int bcCenterx = (bx + cx) / 2;
        int bcCentery = (by + cy) / 2;

        drawFractal(g, ax, ay, side / 2, depth + 1);
        drawFractal(g, acCenterx, acCentery, side / 2, depth + 1);
        drawFractal(g, abCenterx, abCentery, side / 2, depth + 1);

    }

    private class AlgoKeyListener extends KeyAdapter {

        @Override
        public void keyReleased(KeyEvent event) {
            if (event.getKeyChar() >= '0' && event.getKeyChar() <= '9') {
                int depth = event.getKeyChar() - '0';
                setData(depth);
            }
        }
    }
}